#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int sendfd(int fd, void *ptr, int nbytes, int sendfd)
{
	struct msghdr msg;
	struct iovec iov[1];

	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	iov[0].iov_base = ptr;
	iov[0].iov_len = nbytes;
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

 	union
	{
		struct cmsghdr cm;
		char control[CMSG_SPACE(sizeof(int))];
	}control_un;
	
	struct cmsghdr *cmptr;

	msg.msg_control = control_un.control;
	msg.msg_controllen = sizeof(control_un.control);
	
	cmptr = CMSG_FIRSTHDR(&msg);
	cmptr->cmsg_len = CMSG_LEN(sizeof(int));
	cmptr->cmsg_level = SOL_SOCKET;
	cmptr->cmsg_type = SCM_RIGHTS;
	*((int *)CMSG_DATA(cmptr)) = sendfd;

	return (sendmsg(fd,&msg, 0));
};

int main()
{
	int fd[2];
	char szfd[12];
	
	socketpair(AF_LOCAL, SOCK_STREAM, 0, fd);
	if(fork() == 0)
	{
		close(fd[0]);
		sprintf(szfd, "%d", fd[1]);
		execl("./worker", "worker", szfd, (char *)0);
		perror("execl");
	}
	close(fd[1]);

	char szRecv[1024] = {0};
	
	int listen_fd = socket(AF_INET,  SOCK_STREAM, 0);
	if(listen_fd <= 0)
	{
		perror("create socket");
		return -1;
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(10086);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	int rst = bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr));
	if(0 != rst)
	{
		perror("socket bind");
		printf("%d \t %s\n", errno, strerror(errno));
		return -1;
	}

	rst = listen(listen_fd, 20);
	if(0 != rst)
	{
		perror("socket listen");
		return -1;
	}

	for( ; ;)
	{
		int connfd = accept(listen_fd, NULL, NULL);
		printf("recv a connection from client!fd %d\n", connfd);
		int rst = sendfd(fd[0], (void *)"", 1, connfd);
		if(rst == -1)
		{
			printf("send msg error: %d: %s", errno, strerror(errno));
		}
		printf("send connfd to worker!\n");
	}

	return 0;
}
